﻿using System.ComponentModel;
using System.Reflection;
using Foundation.Core;
using Foundation.Entity;
using Foundation.ObjectTracing;
using Newtonsoft.Json;

namespace Dyao.Book.Core
{
    /// <summary>
    /// 对象跟踪扩展：
    /// </summary>
    public static class EntityObjectTracingExtensions
    {
        public static string TracingReport<TEntity>(this IObjectTracing<TEntity> tracing)
            where TEntity : class, IEntity
        {
            if (tracing == null) throw new ArgumentNullException(nameof(tracing));

            switch (tracing.ChangeTrackingStatus)
            {
                case ObjectTrackingStatus.Added: return "新增";
                case ObjectTrackingStatus.Deleted: return "删除";
                case ObjectTrackingStatus.Changed: return ChangedReport(tracing);
                default: return "不变";
            }
        }

        private static string ChangedReport<TEntity>(IObjectTracing<TEntity> tracing)
        {
            var changeds = new List<string>();

            var type = typeof(TEntity);
            var current = tracing.GetCurrent();
            var original = tracing.GetOriginal();
            foreach (var p in tracing.ChangedProperties)
            {
                var property = type.GetProperty(p);
                var currentValue = property.GetValue(current);
                var originalValue = property.GetValue(original);
                string name = string.Empty;
                var descAttr = property.GetCustomAttribute<DescriptionAttribute>();
                if (descAttr == null)
                    name = property.Name;
                else
                    name = descAttr.Description;

                string oriVal = Convert.ToString(originalValue),
                    curVal = Convert.ToString(currentValue);

                if (IsBooleanProperty(property))
                {
                    oriVal = Convert.ToBoolean(originalValue) ? "是" : "否";
                    curVal = Convert.ToBoolean(currentValue) ? "是" : "否";
                }

                if (property.PropertyType.IsEnum)
                {
                    oriVal = EnumHelper.GetDescription(originalValue);
                    curVal = EnumHelper.GetDescription(currentValue);
                }

                changeds.Add($"{name}:{oriVal}->{curVal}");
            }

            return $"{string.Join("\r\n", changeds)}";
        }

        /// <summary>
        /// 是否为bool类型
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        private static bool IsBooleanProperty(PropertyInfo property)
        {
            Type type = property.PropertyType;
            return type == typeof(bool) ||
                   (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)
                    && Nullable.GetUnderlyingType(type) == typeof(bool));
        }
    }
}
